/*++

Copyright (c) 2007  Microsoft Corporation 

Filename: 

    RackVirtualizer.cs

Abstract: 

    Interface for Rack Virtulize
     
--*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using Visio = Microsoft.Office.Interop.Visio;
using UtilityManager;
using System.Collections;
using System.Globalization;
using System.Data;

namespace VisioManager
{
    class RackVirtualizer
    {
        #region public / private variables

        // Rack Document
        private Document _rackDocument;

        // Visio document
        private Visio.Document visioDocument;

        // Data table to store & sort analyzis data
        private DataTable serverTable;

        #endregion public / private variables

        #region Properties

        public Visio.Document VisioDocument
        {
            set { visioDocument = value; }
        }

        internal Visio.DataRecordset RackDR
        {
            get
            {
                return _rackDocument.RackDR;
            }
            set { _rackDocument.RackDR = value; }
        }

        internal Visio.DataRecordset ServerDR
        {
            get
            {
                    return _rackDocument.ServerDR;
            }
            set { _rackDocument.ServerDR = value; }
        }

        internal Document RackDocument
        {
            set { _rackDocument = value; }
        }

        #endregion Properties

        #region Methods

        /// <summary>
        /// Virtualize the selected racks on the active document
        /// </summary>
        public void VirtualizeRack()
        {
            bool rackFound = false;

            try
            {

                if (_rackDocument == null)
                {
                    return;
                }

                // Check if diagram generation in progess
                if (_rackDocument.diagramGenerationOn)
                {
                    MessageBox.Show(Global.GetResourceString("DocumentVirtualizeStartDiagram"),
                        Global.GetResourceString("MessageBoxCaption"),
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Information,
                        MessageBoxDefaultButton.Button1);
                    // Start Virtualize failed. Return
                    return;
                }

                // Check if analyze already in progess
                if (_rackDocument.analysisOn)
                {
                    MessageBox.Show(Global.GetResourceString("DocumentVirtualizeStartAnalyze"),
                        Global.GetResourceString("MessageBoxCaption"),
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Information,
                        MessageBoxDefaultButton.Button1);
                    // Start Virtualize failed. Return False
                    return;
                }

                if (this.RackDR == null)
                {
                    this.RackDR = Document.GetDataRecordset(visioDocument.DataRecordsets, Global.RackDataRecordSetName);

                    if (this.RackDR == null)
                    {
                        MessageBox.Show(string.Format(CultureInfo.CurrentCulture,
                            Global.GetResourceString("MessageBoxAnalyseThenVirtualize"), Global.RackDataRecordSetName),
                            Global.GetResourceString("MessageBoxCaption"),
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                        return;
                    }
                }

                // Get active page reference
                Visio.Page currPage = visioDocument.Application.ActivePage;

                // Check if page type property exist
                if (!Convert.ToBoolean(currPage.PageSheet.get_CellExistsU(
                    Global.PageTemplateUserProp,
                    (short)Visio.VisExistsFlags.visExistsAnywhere)))
                {
                    // Page do not have PageType property
                    MessageBox.Show(Global.GetResourceString("MessageImportData"),
                        Global.GetResourceString("Exception_MsgBox_Caption"),
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Information,
                        MessageBoxDefaultButton.Button1);
                    return;
                }

                // Fetch the page type value
                string pageType = currPage.PageSheet.get_CellsU(Global.PageTemplateUserProp).FormulaU.Trim('\"'); ;

                switch (pageType)
                {
                    case Global.PageTemplateColo:
                        // Active page is a colo page. Virtualize the selected rack
                        if (Global.VisioApp.ActiveWindow == null)
                            return;

                        Visio.Selection racks = Global.VisioApp.ActiveWindow.Selection;

                        if (racks.Count == 0)
                        {
                            MessageBox.Show(Global.GetResourceString("MessageSelectRackVirtualize"),
                                    Global.GetResourceString("Exception_MsgBox_Caption"),
                                        MessageBoxButtons.OK, MessageBoxIcon.Information,
                                        MessageBoxDefaultButton.Button1);
                            return;
                        }
                        // Virtualize all the selected racks
                        foreach (Visio.Shape currShape in racks)
                        {
                            if (String.Compare(Document.GetShapeProperty(currShape, Global.PropRackVirtualizable), "1") == 0)
                            {
                                rackFound = true;
                                ViewRackDetails(currShape, true);
                            }
                        }
                        if (!rackFound)
                        {
                            // No racks found on the current page
                            MessageBox.Show(Global.GetResourceString("MessageRackNotAnalyzed"),
                                Global.GetResourceString("Exception_MsgBox_Caption"),
                                MessageBoxButtons.OK, MessageBoxIcon.Information,
                                MessageBoxDefaultButton.Button1);
                        }
                        break;

                    case Global.PageTemplateRack:
                        // Active page is a rack page. Virtualize only the active rack
                        foreach (Visio.Shape currShape in currPage.Shapes)
                        {
                            // Check for rack shape
                            if (currShape.Master != null &&
                                String.Compare(currShape.Master.NameU, Global.RackMasterName) == 0)
                            {
                                // Make sure rack is not a virtual rack
                                if (String.Compare(Document.GetShapeProperty(currShape, Global.UserVirtualRack), "FALSE") == 0)
                                {
                                    // Valid rack shape found
                                    rackFound = true;

                                    // Virtualize the rack shape
                                    ViewRackDetails(Document.GetColoRackFromDetailRack(currShape, visioDocument, RackDR), true);
                                }
                            }
                        }
                        if (!rackFound)
                        {
                            // No racks found on the current page
                            MessageBox.Show(Global.GetResourceString("MessageNoRackFoundVirtualize"),
                                Global.GetResourceString("Exception_MsgBox_Caption"),
                                MessageBoxButtons.OK, MessageBoxIcon.Information,
                                MessageBoxDefaultButton.Button1);
                        }
                        break;
                }
            }
            catch (RackException ex)
            {
                // Exception from sub function. Pass on to entry point
                throw new RackException("Virtualize", ex.InnerException);
            }
            catch (Exception ex)
            {
                // Exception from current function
                throw new RackException("Virtualize", ex);
            }
        }

        /// <summary>
        /// Display rack in detail with all the servers present in the selected rack.
        /// Based on the flag value display the proposed virtual image also.
        /// </summary>
        /// <param name="visioShape">Select rack shape</param>
        /// <param name="virtualize">True to display virtual rack image</param>
        public void ViewRackDetails(Visio.Shape visioShape, bool virtualize)
        {
            string coloName = string.Empty;
            string rackName = string.Empty;
            Visio.Page detailPage = null;
            Visio.Shape rackShape = null;
            Visio.Shape virtualRackShape = null;
            Visio.Shape serverShape = null;
            Visio.Shape coloRackShape = null;

            try
            {
                // Check for valid shape
                if (_rackDocument == null || visioShape == null)
                {
                    return;
                }

                // Check if virtualize flag set
                if (virtualize)
                {
                    // Check if diagram generation in progess
                    if (_rackDocument.diagramGenerationOn)
                    {
                        MessageBox.Show(Global.GetResourceString("DocumentVirtualizeStartDiagram"),
                            Global.GetResourceString("MessageBoxCaption"),
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Information,
                            MessageBoxDefaultButton.Button1);
                        // Start Virtualize failed. Return
                        return;
                    }

                    // Check if analyze already in progess
                    if (_rackDocument.analysisOn)
                    {
                        MessageBox.Show(Global.GetResourceString("DocumentVirtualizeStartAnalyze"),
                            Global.GetResourceString("MessageBoxCaption"),
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Information,
                            MessageBoxDefaultButton.Button1);
                        // Start Virtualize failed. Return False
                        return;
                    }

                    coloRackShape = visioShape;

                    if (coloRackShape != null && String.Compare(Document.GetShapeProperty(coloRackShape, Global.PropRackVirtualizable),
                        "1") != 0)
                    {
                        MessageBox.Show(Global.GetResourceString("MessageRackNonVirtualizable"),
                            Global.GetResourceString("MessageBoxCaption"),
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Information,
                            MessageBoxDefaultButton.Button1);
                        return;
                    }
                }

                Visio.Masters DetailMasters = null;

                try
                {
                    DetailMasters = Global.VisioApp.Documents[Global.RackServerStencil].Masters;
                }
                catch (System.Runtime.InteropServices.COMException)
                {
                    MessageBox.Show(string.Format(CultureInfo.CurrentCulture,
                        Global.GetResourceString("MessageFileNotFound"), Global.RackServerStencil),
                        Global.GetResourceString("MessageBoxCaption"),
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Error,
                        MessageBoxDefaultButton.Button1);
                    return;
                }
                Visio.Master RackMaster = DetailMasters.get_ItemU(Global.RackMasterName);
                Visio.Master SeverMaster = DetailMasters.get_ItemU(Global.ServerMasterName);

                if (this.ServerDR == null)
                {
                    this.ServerDR = Document.GetDataRecordset(visioDocument.DataRecordsets, Global.ServerDataRecordSetName);

                    if (this.ServerDR == null)
                    {
                        MessageBox.Show(string.Format(CultureInfo.CurrentCulture,
                            Global.GetResourceString("MessageDataRecordSetNotFound"), Global.ServerDataRecordSetName),
                            Global.GetResourceString("MessageBoxCaption"),
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                        return;
                    }
                }

                if (this.RackDR == null)
                {
                    this.RackDR = Document.GetDataRecordset(visioDocument.DataRecordsets, Global.RackDataRecordSetName);

                    if (this.RackDR == null)
                    {
                        MessageBox.Show(string.Format(CultureInfo.CurrentCulture,
                            Global.GetResourceString("MessageDataRecordSetNotFound"), Global.RackDataRecordSetName),
                            Global.GetResourceString("MessageBoxCaption"),
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                        return;
                    }
                }

                if (Global.ShapePropertyExist(visioShape, Global.PropColoName))
                {
                    coloName = visioShape.get_Cells(Global.PropColoNameValue).get_ResultStr((short)Visio.VisUnitCodes.visNoCast);
                }

                if (Global.ShapePropertyExist(visioShape, Global.PropRackName))
                {
                    rackName = visioShape.get_Cells(Global.PropRackNameValue).get_ResultStr((short)Visio.VisUnitCodes.visNoCast);
                }

                string rackPageName = coloName + rackName;

                Array rackRowIDs = RackDR.GetDataRowIDs(
                    "[" + RackDR.DataColumns[Global.RackFieldColoName].Name + "] Like '" + coloName + "' AND " +
                    "[" + RackDR.DataColumns[Global.RackFieldRackName].Name + "] Like '" + rackName + "'");
                if (rackRowIDs.Length == 0)
                {
                    MessageBox.Show(Global.GetResourceString("MessageRackShapeNotFound"),
                            Global.GetResourceString("MessageBoxCaption"),
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Information,
                            MessageBoxDefaultButton.Button1);
                    return;
                }

                try
                {
                    // Get the detail page of current rack if already exist
                    detailPage = visioDocument.Pages.get_ItemU(rackPageName);

                    // Clear existing shapes on the selected page
                    detailPage.Application.ActiveWindow.Page = detailPage;
                    if (detailPage.Shapes.Count > 0)
                    {
                        detailPage.Application.ActiveWindow.SelectAll();
                        detailPage.Application.ActiveWindow.Selection.Delete();
                    }
                }
                catch (System.Runtime.InteropServices.COMException)
                {
                    // Page not found. Add new page
                    detailPage = visioDocument.Pages.Add();
                    detailPage.NameU = rackPageName;
                }
                // Add page type property & set to rack
                Document.AddPageProperty(detailPage, Global.PageTemplateRack);

                
                // Find the rack data for current rack
                foreach (int rackRowID in rackRowIDs)
                {
                    // Drop rack linked to the datarecord set
                    rackShape = detailPage.DropLinked(RackMaster, 1.375, 1, RackDR.ID, rackRowID, true);

                    Document.UpdateShapeProperty(rackShape, (short)Visio.VisSectionIndices.visSectionUser, Global.VirtualRack, "FALSE");

                    AddLabel(detailPage, "BeforeRackLabel", Global.GetResourceString("LabelBeforeVirtualize"),
                        0.5, 10, 2.25, 10);

                    // If virtualize flag is set drop one more virtual rack
                    if (virtualize)
                    {
                        virtualRackShape = detailPage.DropLinked(RackMaster, 5.625, 1, RackDR.ID, rackRowID, true);
                        Document.UpdateShapeProperty(virtualRackShape, (short)Visio.VisSectionIndices.visSectionUser, Global.VirtualRack, "TRUE");
                        AddLabel(detailPage, "AfterRackLabel", Global.GetResourceString("LabelAfterVirtualize"),
                            4.5, 10, 7, 10);
                    }
                    break;
                }

                Array ServerArray = ServerDR.GetDataRowIDs(
                    "[" + ServerDR.DataColumns[Global.ServerFieldColoName].Name + "] Like '" + coloName + "' AND " +
                    "[" + ServerDR.DataColumns[Global.ServerFieldRackName].Name + "] Like '" + rackName + "'");

                ArrayList virtualServerList = new ArrayList();

                if (serverTable != null)
                {
                    // Clear server table for new scan
                    serverTable.Clear();
                }

                bool serverNotConnected = false;
                short serverSize = 0;
                short begin = 0;


                // Loop through each server in current rack
                foreach (int serverRowID in ServerArray)
                {
                    if (rackShape != null)
                    {
                        // Drop detail level rack linked to the datarecord set
                        serverShape = detailPage.DropLinked(SeverMaster, 0, 0, ServerDR.ID, serverRowID, false);

                        // Connect server shape with rack shape
                        if (!serverNotConnected)
                        {
                            string uSize = Document.GetShapePropertyResult(serverShape, Global.PropUCount);
                            serverSize = 0;
                            double d; 

                            if (!String.IsNullOrEmpty(uSize) && Double.TryParse(uSize,out d))
                            {
                                double serverSizeD = Convert.ToDouble(uSize,CultureInfo.CurrentCulture);
                                serverSize = Convert.ToInt16(serverSizeD * 2);
                            }

                            if ((begin + serverSize) > 102)
                            {
                                serverNotConnected = true;
                                MessageBox.Show(Global.GetResourceString("MessageRackServerLimitExceed"),
                                    Global.GetResourceString("MessageBoxCaption"),
                                    MessageBoxButtons.OK,
                                    MessageBoxIcon.Information,
                                    MessageBoxDefaultButton.Button1);
                            }
                            else
                            {

                                ConnectServerWithRack(serverShape, rackShape, begin);

                            }

                            begin += serverSize;

                            // Update server virtualizable property based on the cpu usage
                            UpdateServerVirtualizableProp(serverShape);

                        }

                        string serverCpuUsage = Document.GetShapeProperty(serverShape, Global.PropCpuUsage).Trim('%');

                        if (!String.IsNullOrEmpty(serverCpuUsage) &&
                            String.Compare(serverCpuUsage, Global.NA) != 0)
                        {
                            int cpuUsage = Convert.ToInt32(serverCpuUsage, CultureInfo.CurrentCulture);
                            if (virtualize)
                            {
                                // Store the server data in a data table to perform virtualize calculation

                                string networkName = Document.GetShapeProperty(serverShape, Global.PropNetworkName);
                                int powerRating = Convert.ToInt32(Document.GetShapeProperty(serverShape, Global.PropPowerRating).Trim('W', 'w'), CultureInfo.CurrentCulture);
                                int rackSpace = Convert.ToInt32(Document.GetShapeProperty(serverShape, Global.PropRackSpaceUsed).Trim('U', 'u'), CultureInfo.CurrentCulture);
                                int totalMem = Convert.ToInt32(Document.GetShapeProperty(serverShape, Global.PropTotalMem), CultureInfo.CurrentCulture);
                                int availMem = Convert.ToInt32(Document.GetShapeProperty(serverShape, Global.PropAvailMem), CultureInfo.CurrentCulture);
                                string virtualServer = Document.GetShapeProperty(serverShape, Global.PropIsVirtual).Trim(' ');
                                int memUsage = 0;

                                if (totalMem != 0)
                                {
                                    memUsage = Convert.ToInt32(100 - ((availMem * 100) / totalMem), CultureInfo.CurrentCulture);
                                }

                                virtualServerList.Clear();

                                virtualServerList.Add(serverRowID);
                                virtualServerList.Add(networkName);
                                virtualServerList.Add(powerRating);
                                virtualServerList.Add(rackSpace);
                                virtualServerList.Add(cpuUsage);
                                virtualServerList.Add(memUsage);
                                virtualServerList.Add(virtualServer);

                                CreateServerTable(virtualServerList);
                            }
                        }
                        if (serverNotConnected && serverShape != null)
                        {
                            //Shape not connected. Delete
                            serverShape.Delete();
                        }
                    }

                    else
                    {
                        MessageBox.Show(Global.GetResourceString("MessageRackShapeNotFound"),
                            Global.GetResourceString("MessageBoxCaption"),
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Information,
                            MessageBoxDefaultButton.Button1);
                        return;
                    }
                }

                if (virtualize)
                {
                    // Merge servers from the bottom of the list with the servers from the top of the list
                    Visio.Shape virtualServerShape = null;

                    int powerSaved = 0;
                    int rackSpaceSaved = 0;

                    if (serverTable != null)
                    {
                        DataRow[] fwdList = serverTable.Select("CpuUsage <= " + Global.CpuUsageThreshold.ToString(CultureInfo.CurrentCulture) + "AND IsVirtual <> 'True'", "PowerRating DESC,RackSpaceUsed ASC,CpuUsage DESC,MemUsage DESC");
                        DataRow[] nonVirtualServerList = serverTable.Select("CpuUsage > " + Global.CpuUsageThreshold.ToString(CultureInfo.CurrentCulture) + "OR IsVirtual = 'True'", "PowerRating ASC,RackSpaceUsed DESC,CpuUsage ASC,MemUsage ASC");


                        int bckPtr = fwdList.Length - 1;
                        int virtualServersCount = fwdList.Length / Global.MaxServerConsolidate;

                        if (fwdList.Length % Global.MaxServerConsolidate != 0)
                        {
                            virtualServersCount++;
                        }

                        short connectorPt = 0;
                        serverNotConnected = false;
                        Visio.Shape tempShape = null;
                        serverSize = 0;

                        for (int fwdPtr = 0; fwdPtr < virtualServersCount; fwdPtr++)
                        {
                            int serverRowID = Convert.ToInt32(fwdList[fwdPtr][Global.TableColServerId], CultureInfo.CurrentCulture);
                            virtualServerShape = detailPage.DropLinked(SeverMaster, 0, 0, ServerDR.ID, serverRowID, false);
                            if (!serverNotConnected)
                            {
                                UpdateServerVirtualizableProp(virtualServerShape);

                                string uSize = Document.GetShapePropertyResult(virtualServerShape, Global.PropUCount);
                                serverSize = 0;

                                if (!String.IsNullOrEmpty(uSize))
                                {
                                    double serverSizeD = Convert.ToDouble(uSize,CultureInfo.CurrentCulture);
                                    serverSize = Convert.ToInt16(serverSizeD * 2,CultureInfo.CurrentCulture);
                                }

                                if ((connectorPt + serverSize) > 102)
                                {
                                    serverNotConnected = true;
                                    MessageBox.Show(Global.GetResourceString("MessageRackServerLimitExceed"),
                                        Global.GetResourceString("MessageBoxCaption"),
                                        MessageBoxButtons.OK,
                                        MessageBoxIcon.Information,
                                        MessageBoxDefaultButton.Button1);
                                }
                                else
                                {
                                    ConnectServerWithRack(virtualServerShape, virtualRackShape, connectorPt);
                                }

                                connectorPt += serverSize;

                                if (!serverNotConnected)
                                {
                                    tempShape = virtualServerShape;
                                }
                            }

                            for (int ctr = 1; ctr < Global.MaxServerConsolidate; ctr++)
                            {
                                if (fwdPtr >= bckPtr)
                                    break;
                                powerSaved += Convert.ToInt32(fwdList[bckPtr][Global.TableColPowerRating], CultureInfo.CurrentCulture);
                                rackSpaceSaved += Convert.ToInt32(fwdList[bckPtr][Global.TableColRackSpaceUsed], CultureInfo.CurrentCulture);
                                Document.UpdateShapeProperty(virtualServerShape,
                                    (short)Visio.VisSectionIndices.visSectionProp,
                                    Global.GetResourceString("FieldVirtualServer") + ctr.ToString(CultureInfo.CurrentCulture),
                                    fwdList[bckPtr][Global.TableColServerName].ToString());
                                bckPtr--;
                            }
                            if (serverNotConnected && virtualServerShape != null)
                            {
                                //Shape not connected. Delete
                                virtualServerShape.Delete();
                            }
                        }

                        //serverNotConnected = false;

                        foreach (DataRow serverRow in nonVirtualServerList)
                        {
                            int serverRowID = Convert.ToInt32(serverRow[Global.TableColServerId], CultureInfo.CurrentCulture);
                            virtualServerShape = detailPage.DropLinked(SeverMaster, 0, 0, ServerDR.ID, serverRowID, false);

                            if (!serverNotConnected)
                            {
                                UpdateServerVirtualizableProp(virtualServerShape);

                                string uSize = Document.GetShapePropertyResult(virtualServerShape, Global.PropUCount);
                                serverSize = 0;

                                if (!String.IsNullOrEmpty(uSize))
                                {
                                    double serverSizeD = Convert.ToDouble(uSize,CultureInfo.CurrentCulture);
                                    serverSize = Convert.ToInt16(serverSizeD * 2,CultureInfo.CurrentCulture);
                                }

                                if ((connectorPt + serverSize) > 102)
                                {
                                    serverNotConnected = true;
                                    MessageBox.Show(Global.GetResourceString("MessageRackServerLimitExceed"),
                                        Global.GetResourceString("MessageBoxCaption"),
                                        MessageBoxButtons.OK,
                                        MessageBoxIcon.Information,
                                        MessageBoxDefaultButton.Button1);
                                }
                                else
                                {
                                    ConnectServerWithRack(virtualServerShape, virtualRackShape, connectorPt);
                                }

                                connectorPt += serverSize;

                                if (!serverNotConnected)
                                {
                                    tempShape = virtualServerShape;
                                }
                            }

                            if (serverNotConnected && virtualServerShape != null)
                            {
                                //Shape not connected. Delete
                                virtualServerShape.Delete();
                            }
                        }

                        // Add power & space saved indicators
                        AddSavedShape(detailPage, virtualRackShape, tempShape,
                                            powerSaved.ToString(CultureInfo.CurrentCulture), rackSpaceSaved.ToString(CultureInfo.CurrentCulture));
                    }
                    else
                    {
                        // Rack not analyzed
                        Document.UpdateShapeProperty(visioShape,
                            (short)Visio.VisSectionIndices.visSectionUser,
                            Global.RackVirtualizable, "0");
                    }
                }

                // Drop page label
                Document.DropPageLabel(detailPage);

                if (detailPage != null &&
                    detailPage.Application != null &&
                    detailPage.Application.ActiveWindow != null)
                {
                    detailPage.Application.ActiveWindow.DeselectAll();
                }

            }
            catch (RackException ex)
            {
                // Exception from sub function. Pass on to entry point
                throw new RackException("View Rack Details", ex.InnerException);
            }
            catch (Exception ex)
            {
                // Exception from current function
                throw new RackException("View Rack Details", ex);
            }
        }

        /// <summary>
        /// Add power & space saved indicators
        /// </summary>
        /// <param name="visioPage"></param>
        /// <param name="rackShape"></param>
        /// <param name="serverShape"></param>
        /// <param name="powerSaved"></param>
        /// <param name="spaceSaved"></param>
        private static void AddSavedShape(Visio.Page visioPage, Visio.Shape rackShape,
            Visio.Shape serverShape, string powerSaved, string spaceSaved)
        {
            Visio.Shape powerSaveShape = null;
            Visio.Shape spaceSaveShape = null;
            Visio.Shape balloonShape = null;
            Visio.Master powerSaveMaster = null;
            Visio.Master spaceSaveMaster = null;
            Visio.Master balloonMaster = null;

            try
            {
                powerSaveMaster = Global.VisioApp.Documents[Global.RackServerStencil].Masters.get_ItemU(Global.BraceMasterName);
                spaceSaveMaster = Global.VisioApp.Documents[Global.RackServerStencil].Masters.get_ItemU(Global.SpaceBarMasterName);
                balloonMaster = Global.VisioApp.Documents[Global.RackServerStencil].Masters.get_ItemU(Global.BalloonMasterName);
            }
            catch (System.Runtime.InteropServices.COMException)
            {
                MessageBox.Show(string.Format(CultureInfo.CurrentCulture,
                    Global.GetResourceString("MessageFileNotFound"), Global.RackServerStencil),
                    Global.GetResourceString("MessageBoxCaption"),
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error,
                    MessageBoxDefaultButton.Button1);
                return;
            }

            // Get rack shapes height, width, pinX & pinY
            double rackHt = rackShape.get_CellsSRC(
                    (short)Visio.VisSectionIndices.visSectionObject,
                    (short)Visio.VisRowIndices.visRowXFormOut,
                    (short)Visio.VisCellIndices.visXFormHeight).ResultIU;

            double rackWt = rackShape.get_CellsSRC(
                    (short)Visio.VisSectionIndices.visSectionObject,
                    (short)Visio.VisRowIndices.visRowXFormOut,
                    (short)Visio.VisCellIndices.visXFormWidth).ResultIU;

            double rackPinX = rackShape.get_CellsSRC(
            (short)Visio.VisSectionIndices.visSectionObject,
            (short)Visio.VisRowIndices.visRowXFormOut,
            (short)Visio.VisCellIndices.visXFormPinX).ResultIU;

            double rackPinY = rackShape.get_CellsSRC(
            (short)Visio.VisSectionIndices.visSectionObject,
            (short)Visio.VisRowIndices.visRowXFormOut,
            (short)Visio.VisCellIndices.visXFormPinY).ResultIU;

            double serverHt = serverShape.get_CellsSRC(
                    (short)Visio.VisSectionIndices.visSectionObject,
                    (short)Visio.VisRowIndices.visRowXFormOut,
                    (short)Visio.VisCellIndices.visXFormHeight).ResultIU;

            double serverPinY = serverShape.get_CellsSRC(
            (short)Visio.VisSectionIndices.visSectionObject,
            (short)Visio.VisRowIndices.visRowXFormOut,
            (short)Visio.VisCellIndices.visXFormPinY).ResultIU;

            // Drop power saved shape
            double powerSaveShapepinX = rackPinX - rackWt / 2;
            double powerSaveShapepinY = rackPinY + rackHt / 2;

            powerSaveShape = visioPage.Drop(powerSaveMaster, powerSaveShapepinX, powerSaveShapepinY);
            powerSaveShape.Text = powerSaveShape.Text + " " + powerSaved + "W";
            powerSaveShape.get_CellsSRC(
                        (short)Visio.VisSectionIndices.visSectionObject,
                        (short)Visio.VisRowIndices.visRowXFormOut,
                        (short)Visio.VisCellIndices.visXFormWidth).FormulaU = rackHt.ToString(CultureInfo.CurrentCulture);

            // Drop rack space saved indicator
            double spaceSaveShapePinX = rackPinX;
            double spaceSaveShapeBeginY = rackPinY + rackHt;
            double spaceSaveShapeEndY = serverPinY + serverHt;
            spaceSaveShape = visioPage.Drop(spaceSaveMaster, spaceSaveShapePinX, 0);
            spaceSaveShape.Text = spaceSaveShape.Text + " " + spaceSaved + "U";
            spaceSaveShape.get_CellsSRC(
                (short)Visio.VisSectionIndices.visSectionObject,
                (short)Visio.VisRowIndices.visRowXForm1D,
                (short)Visio.VisCellIndices.vis1DBeginY).ResultIU = spaceSaveShapeBeginY;

            spaceSaveShape.get_CellsSRC(
                (short)Visio.VisSectionIndices.visSectionObject,
                (short)Visio.VisRowIndices.visRowXForm1D,
                (short)Visio.VisCellIndices.vis1DEndY).ResultIU = spaceSaveShapeEndY;

            // Drop balloon
            balloonShape = visioPage.Drop(balloonMaster, 7.4167, 9.2292);
            Document.UpdateShapeProperty(balloonShape, (short)Visio.VisSectionIndices.visSectionProp,
                "PowerDrop", powerSaved + "W");
            Document.UpdateShapeProperty(balloonShape, (short)Visio.VisSectionIndices.visSectionProp,
                "SpaceSaved", spaceSaved + "U");
        }

        /// <summary>
        /// Add text label to Visio page
        /// </summary>
        /// <param name="currPage"></param>
        private static void AddLabel(Visio.Page currPage, string labelName, string labelValue,
            double labelX1, double labelY1,
            double labelX2, double labelY2)
        {
            Visio.Shape textBoxShape = null;
            try
            {
                // Get the page label on current page
                textBoxShape = currPage.Shapes[labelName];
            }
            catch (System.Runtime.InteropServices.COMException)
            {
                // If doesnt exist create new
                textBoxShape = currPage.DrawRectangle(labelX1, labelY1, labelX2, labelY2);
            }
            textBoxShape.Text = labelValue;
            textBoxShape.TextStyle = "Normal";
            textBoxShape.LineStyle = "Text Only";
            textBoxShape.FillStyle = "Text Only";
            textBoxShape.NameU = labelName;
        }

        /// <summary>
        /// Update ServerVirtualizable property based on the CPU usage value
        /// </summary>
        /// <param name="serverShape"></param>
        private static void UpdateServerVirtualizableProp(Visio.Shape serverShape)
        {
            try
            {
                string serverCpuUsage = Document.GetShapeProperty(serverShape, Global.PropCpuUsage).Trim('%');
                string virtualServer = Document.GetShapeProperty(serverShape, Global.PropIsVirtual).Trim(' ');

                if (String.IsNullOrEmpty(serverCpuUsage))
                {
                    // Server not yet analyzed
                    Document.UpdateShapeProperty(serverShape, (short)Visio.VisSectionIndices.visSectionUser, Global.PropServerVirtualizable, "0");
                    return;
                }
                if (String.Compare(serverCpuUsage, Global.NA) == 0)
                {
                    // Server analyzed with error
                    Document.UpdateShapeProperty(serverShape, (short)Visio.VisSectionIndices.visSectionUser, Global.PropServerVirtualizable, "2");
                    return;
                }

                int cpuUsage = Convert.ToInt32(serverCpuUsage, CultureInfo.CurrentCulture);
                if (cpuUsage <= Global.CpuUsageThreshold
                    && String.Compare(virtualServer, "TRUE", true,CultureInfo.CurrentCulture) != 0)
                {
                    // Server virtualizable
                    Document.UpdateShapeProperty(serverShape, (short)Visio.VisSectionIndices.visSectionUser, Global.PropServerVirtualizable, "1");
                }
                else
                {
                    // Server not virtualizable
                    Document.UpdateShapeProperty(serverShape, (short)Visio.VisSectionIndices.visSectionUser, Global.PropServerVirtualizable, "3");
                }
            }
            catch (RackException ex)
            {
                // Exception from sub function. Pass on to entry point
                throw new RackException("Update ServerVirtualizable Prop", ex.InnerException);
            }
            catch (Exception ex)
            {
                // Exception from current function
                throw new RackException("Update ServerVirtualizable Prop", ex);
            }
        }

        /// <summary>
        /// Glue server shape with rack shape
        /// </summary>
        /// <param name="serverShape">Server Shape</param>
        /// <param name="rackShape">Rack Shape</param>
        /// <param name="begin">Connection point</param>
        private static bool ConnectServerWithRack(Visio.Shape serverShape, Visio.Shape rackShape, short begin)
        {
            // Connect server shape with rack
            Visio.Cell beginXCell;
            Visio.Cell endXCell;
            try
            {
                //if (begin > 100)
                //{
                //    MessageBox.Show(Global.GetResourceString("MessageRackServerLimitExceed"),
                //        Global.GetResourceString("MessageBoxCaption"),
                //        MessageBoxButtons.OK,
                //        MessageBoxIcon.Information,
                //        MessageBoxDefaultButton.Button1);

                //    //Shape not connected
                //    return true;
                //}

                // Set begin X
                beginXCell = serverShape.get_CellsSRC(
                (short)Visio.VisSectionIndices.visSectionObject,
                (short)Visio.VisRowIndices.visRowXForm1D,
                (short)Visio.VisCellIndices.vis1DBeginX);

                
                    beginXCell.GlueTo(rackShape.get_CellsSRC(
                        (short)Visio.VisSectionIndices.visSectionConnectionPts,
                        begin,
                        (short)Visio.VisCellIndices.visCnnctX));

                    // Set end X
                    endXCell = serverShape.get_CellsSRC(
                    (short)Visio.VisSectionIndices.visSectionObject,
                    (short)Visio.VisRowIndices.visRowXForm1D,
                    (short)Visio.VisCellIndices.vis1DEndX);


                    endXCell.GlueTo(rackShape.get_CellsSRC(
                        (short)Visio.VisSectionIndices.visSectionConnectionPts,
                        Convert.ToInt16(begin + 1),
                        (short)Visio.VisCellIndices.visCnnctX));
                
                
            }
            catch (RackException ex)
            {
                // Exception from sub function. Pass on to entry point
                throw new RackException("Update ServerVirtualizable Prop", ex.InnerException);
            }
            catch (Exception ex)
            {
                // Exception from current function
                throw new RackException("Update ServerVirtualizable Prop", ex);
            }
            //Shape connected
            return false;
        }

        /// <summary>
        /// Create server table to store & sort analyze data
        /// </summary>
        /// <param name="dataArr">Data array</param>
        private void CreateServerTable(ArrayList dataArr)
        {
            try
            {
                if (serverTable == null)
                {
                    // Create new serverTable
                    serverTable = new DataTable("ServerTable");

                    serverTable.Locale = CultureInfo.CurrentCulture;

                    // Add data columns
                    serverTable.Columns.Add(Global.TableColServerId, typeof(object));
                    serverTable.Columns.Add(Global.TableColServerName, typeof(string));
                    serverTable.Columns.Add(Global.TableColPowerRating, typeof(int));
                    serverTable.Columns.Add(Global.TableColRackSpaceUsed, typeof(int));
                    serverTable.Columns.Add(Global.TableColCpuUsage, typeof(int));
                    serverTable.Columns.Add(Global.TableColMemUsage, typeof(int));
                    serverTable.Columns.Add(Global.TableColIsVirtual, typeof(string));
                }

                // Add data row from the array list
                serverTable.Rows.Add(dataArr.ToArray());
            }
            catch (RackException ex)
            {
                // Exception from sub function. Pass on to entry point
                throw new RackException("Create Server Table", ex.InnerException);
            }
            catch (Exception ex)
            {
                // Exception from current function
                throw new RackException("Create Server Table", ex);
            }
        }

        #endregion Methods
    }
}
